package net.ikenway.springboot.demo.Controller;

import com.google.gson.Gson;
import net.ikenway.springboot.demo.Model.Dto.*;
import net.ikenway.springboot.demo.Model.Entity.User;
import net.ikenway.springboot.demo.Service.Implement.AuthenticationService;
import net.ikenway.springboot.demo.Service.Implement.UserDetailsServiceImpl;
import net.ikenway.springboot.demo.Utils.TCaptchaVerifyUtil;
import net.ikenway.springboot.demo.Utils.ValidateErrorMsgUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.persistence.EntityExistsException;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.Map;

/**
 * @author MasterKenway <zk@ikenway.net>
 * @Description
 * @date Created Date 12/14/2020
 */
@RestController
@RequestMapping(value = "/api/auth")
public class AuthController {

    private final AuthenticationService authenticationService;

    private final TCaptchaVerifyUtil tCaptchaVerifyUtil;

    private final UserDetailsServiceImpl userDetailsService;


    @Autowired
    public AuthController(AuthenticationService authenticationService,
                          TCaptchaVerifyUtil tCaptchaVerifyUtil,
                          UserDetailsServiceImpl userDetailsService) {
        this.authenticationService = authenticationService;
        this.tCaptchaVerifyUtil = tCaptchaVerifyUtil;
        this.userDetailsService = userDetailsService;
    }

    @RequestMapping(value = "/register", method = RequestMethod.POST)
    public ResponseBodyDto register(
            @Valid @RequestParam(value = "username") @NotNull(message = "用户名不能为空") @NotEmpty(message = "用户名不能为空") @Email(message = "email") String username,
            @Valid @NotNull @NotEmpty @RequestParam(value = "password") String password,
    @Valid @NotNull @NotEmpty @RequestParam(value = "passwordDouble") String passwordDouble) {
        try {
            if (!password.equals(passwordDouble)) throw new Exception("两次密码不一致");
            authenticationService.register(username, password);
        } catch (EntityExistsException exception) {
            return new ResponseBodyDto(500, "用户已存在");
        } catch (Exception exception) {
            return new ResponseBodyDto(500, exception.getMessage());
        }
        return new ResponseBodyDto(200, "注册成功，跳转登录界面");
    }

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public ResponseBodyDto login(
            @Valid @RequestParam(value = "username") @NotNull(message = "用户名不能为空") @NotEmpty(message = "用户名不能为空") @Email(message = "email") String username,
            @Valid @NotNull @NotEmpty @RequestParam(value = "password") String password) {

        String token = null;
        try {
            token = this.authenticationService.login(username, password);
        } catch (UsernameNotFoundException | BadCredentialsException exception) {
            return new ResponseBodyDto(500, "用户名或密码错误");
        } catch (DisabledException disabledException) {
            return new ResponseBodyDto(500, "用户名已被停用");
        } catch (Exception exception) {
            return new ResponseBodyDto(500, exception.getMessage());

        }
//        if (token ==null) {
//            return new ResponseBodyDto(500, "用户不存在");
//        }
        Map<String, Object> data = new HashMap<>();
        data.put("token", token);
        return new ResponseBodyDto(200, "用户登录成功", data);
    }

    @RequestMapping(value = "/validate", method = RequestMethod.POST)
    public ResponseBodyDto loginValidate(@RequestBody TencentValidateRequestDto tencentValidateRequestDto, HttpServletRequest request) {
        try {
            TencentValidateResponseDto tencentValidateResponseDto = this.tCaptchaVerifyUtil.validate(tencentValidateRequestDto.getTicket(), tencentValidateRequestDto.getRandStr(), request.getRemoteAddr());
            if (tencentValidateResponseDto.getResponse() != 1)
                throw new Exception(tencentValidateResponseDto.getErrMsg());
        } catch (Exception exception) {
            return new ResponseBodyDto(400, exception.getMessage());
        }

        return new ResponseBodyDto(200, "验证成功");
    }

    @RequestMapping(value = "/loginByWechat", method = RequestMethod.POST)
    public ResponseBodyDto loginByWechat(String code) {
        try {
            if (code == null || code.isEmpty()) throw new Exception("code 不能为空");

            Map<String, Object> data = new HashMap<>();
            String token = null;

            WechatOAuthResponseDto wechatOAuthResponseDto = authenticationService.wechatCode2Session(code);

            if (wechatOAuthResponseDto.getErrcode() != null && wechatOAuthResponseDto.getErrcode() != 0) {
                throw new Exception(wechatOAuthResponseDto.getErrmsg());
            } else {
                try {
                    userDetailsService.loadUserByUsername(wechatOAuthResponseDto.getOpenid());
                    token = this.authenticationService.loginByWechat(wechatOAuthResponseDto.getOpenid(), wechatOAuthResponseDto.getSessionKey());
                } catch (UsernameNotFoundException usernameNotFoundException) {
                    userDetailsService.create(new User(wechatOAuthResponseDto.getOpenid(), wechatOAuthResponseDto.getSessionKey()));
                    token = this.authenticationService.loginByWechat(wechatOAuthResponseDto.getOpenid(), wechatOAuthResponseDto.getSessionKey());
                    data.put("token", token);
                    return new ResponseBodyDto(200, "登陆成功", data);
                } catch (Exception exception) {
                    return new ResponseBodyDto(500, exception.getMessage());
                }
            }
            data.put("token", token);
            return new ResponseBodyDto(200, "登陆成功", data);
        } catch (Exception exception) {
            return new ResponseBodyDto(500, exception.getMessage());
        }
    }

}
